IMDSv2でセキュリティを強化しましょう
こんにちは、ヌヌです。
セキュリティを強化できるために多様な方法があります。 今回の記事では、簡単に実装するSSRF攻撃を例としてInstance Meta Data Service(IMDS) v2を紹介しようと思います。
EC2インスタンスメタデータとは?
インスタンスメタデータは、インスタンスに関するデータで、実行中のインスタンスを設定または管理するために使用します。
インスタンスメタデータは、ホスト名、イベント、およびセキュリティグループなどでカテゴリ分けされます。
公式ドキュメントの通りで、インスタンスメタデータはインスタンスに関する情報のことで、インスタンスID、使用しているAMI、ホストネームなどの情報を確認できます。この、インスタンスメタデータはInstance Meta Data Service(IMDS)を通じて取得することが可能です。IMDSのローカルipアドレス(169.254.169.254
)にアクセスするとIMDSで確認できる情報のカテゴリーや該当カテゴリー中の情報が確認できます。
使い方
curl http://169.254.169.254/latest/meta-data/{カテゴリー名}
EC2インスタンスに関する多様な情報が得られて有用な機能ですが、代表的にはインスタンスに割り当てされているIAMロール情報など重要な情報も取得できますので注意が必要です。メタデータでIAMロール権限を取得し、その権限を自由に利用できるからです。
割り当てされているIAMロールの確認
curl http://169.254.169.254/latest/meta-data/security-credentials/
IMDS v1
の場合、GETメソッドで上記のコマンドを実行するだけでメタデータの取得が可能になりますので、攻撃者がGETメソッドをインスタンスに送ることが可能であれば攻撃の難易度が比較的に高くないです(IMDS自体は安全)。
しかしIMDS v2
を利用してメタデータを取得するためにはPUTメソッドで発給してもらったTOKENが必要になるので攻撃の難易度が高くなり、より強化されたセキュリティを構成できます。
(IMDS v2に関する詳細や事故事例は臼田さんの記事を参考すると理解しやすいと思います。)
SSRF攻撃は?
SSRF
はServer-Side Request Forgeryの略で、サーバーが行うリクエストを攻撃者が偽造する攻撃です。簡単に話すと攻撃者が脆弱性があるサーバーを利用して内部のサーバーに攻撃リクエストを送る攻撃です。普段の場合、外部から内部サーバーにはアクセスできません。
しかし、内部サーバーへアクセス可能な外部に公開されているサーバーに脆弱性があれば、そのサーバーの権限を利用して内部サーバーへ攻撃リクエストが送れます。内部サーバーはこの攻撃リクエストを正常リクエストだと判断しそのまま実行してしまうようなります。
このようなSSRF攻撃に対してEC2インスタンスに脆弱性があれば、攻撃者はインスタンスのメタデータへのアクセスが可能になり、サーバー内部の情報だけではなくIAM権限を利用した攻撃もできますのでとても危険な攻撃だと言えます。そのため、IMDS v2を使用してSSRF攻撃に対するセキュリティを強化しましょう(インスタンスがメタデータにアクセスできないようメタデータアクセスを無効に設定するのも可能です)。
直接確認してみました
実際の攻撃がある場合、IMDS v1とIMDS v2はどのような結果が発生するのかを簡単なSSRF攻撃環境を構築して直接みてみました。メタデータへアクセス可能で、SSRF脆弱性があるウェブサーバーを用意してS3にアクセスできるのかを試してみました。
インスタンスに攻撃リクエストを送ってIMDSでIAM情報を確認し、その権限を利用してS3にアクセスします。
脆弱性があるウェブサーバー作成
EC2インスタンス作成
ウェブサーバーの設定はAWS公式ドキュメントを参考し、IMDSが使えるように下記の設定を行いました。比較のためメタデータのバージョンを「V1およびV2」で設定しましたが、IMDS v2だけ制限する設定もあります。
- EC2コンソール画面 → インスタンスを起動 →「高度な詳細」項目で、アクセス可能を有効でメタデータバージョンはv1及びv2設定
脆弱性作成
get.php
<?php $target = isset($_GET['target']) ? $_GET['target'] : null; if ($target == null){ echo "no result"; exit(); } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $target); $output = curl_exec($ch); curl_close($ch); print_r($output); ?>
そして脆弱性があるphpファイルを作成します。このコードはGETメソッドのリクエストを受信すると、target
パラメターの値を確認しcurlコマンドで通信を行います。
IMDS V1の場合
targetパラメターにIMDSのアドレスを入れて、公開されているインスタンスへGETリクエストを送ります。
IMDSにアクセス
ami-id ami-launch-index ami-manifest-path block-device-mapping/ events/ hostname iam/ ...
IMDSにアクセスするとメタデータの一覧が確認できます。ここでIAMロールを含め詳細なメタデータ情報が見えます。
インスタンスに付与されているIAMロール情報をみます。その情報としては、IAMのAccessKeyId, SecretAccessKey, Token, Tokenの満了時間などの情報がありました。
もしかして取得したIAMロールにS3にアクセスできる権限があれば深刻な情報漏洩になりやすいです。
バケットリスト取得
% aws s3 ls 2000-00-00 00:00:00 test-very-important-data
オブジェクトリスト取得
% aws s3 ls test-very-important-data 2000-00-00 00:00:00 top_secret.txt
IMDS V2の場合
IMDS V2はPUTメソッドでTokenを発給しなければいけません。IMDS V2を使用するだけでGETメソッドのパラメターを確認してから動作している今回のコードを攻撃するのは難しくなりました。
有効なTokenがなかったり満了されたTokenのリクエストの場合 401-Unauthorizedエラーが発生します。
その他、IMDS V2はX-Forwarded-ForヘッダーがあるリクエストにはTokenを発給しなかったりHop Counter(HttpPutResponseHopLimit)を設定したりするので、IMDS V1よりセキュリティが強化されています。
最後に
IMDS V2を簡単なSSRF攻撃を通じて確認してみました。IMDS V2を使用するだけで多くのセキュリティ強化ができる良い機能だと思います。しかし、IMDS V2が根本的な対策ではありません。セキュリティを強化するためには多様な対策が必要になるので油断しなよう気をつけましょう。